#include "linux/err.h"
#include "linux/export.h"
#include "linux/mfd/si476x-core.h"
#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/timer.h>



//寄存器定义
#define CNF1 0x2a //寄存器定义
#define CNF2 0x29
#define CNF3 0x28
#define RXB0CTRL 0x2b
#define CANINTE 0x60
#define CANCTRL 0xf
#define TXB0CTRL 0x30
#define CANINTF 0x2c


static int major;
static struct class *spi_class;
static struct device *spi_device;
static struct spi_device *g_spi;
 struct spi_device *spi_dev;

void mcp2515_reset(void)
{
    int err;
    unsigned char buf[] = {0xc0};

    err = spi_write(spi_dev, buf, sizeof(buf));
    if(err < 0)
    {
        printk("spi_writeiserror\n");
    }
}

//读寄存器函数
char mcp2515_read_reg(char reg)
{
    char write_buf[] = {0x03 ,reg};
    char read_buf;
    int err;

    err = spi_write_then_read(spi_dev, write_buf, sizeof(write_buf), &read_buf, sizeof(read_buf));
    if(err < 0)
    {
        printk("spi_write_then_read error\n");
        return err;
    }

    return read_buf;

}


//写寄存器
void mcp2515_write_reg(char reg,char value)
{
    int ret;
    char write_buf[]={0x02,reg,value};  //SPI写缓冲区，用于发送写寄存器命令
    ret = spi_write(spi_dev,write_buf,sizeof(write_buf));   //发送SPI写命令
    if(ret < 0)
    {
        printk("mcp2515_write_reg error\n");
    }
 }


void mcp2515_change_regbit(char reg,char mask,char value)
{
    int ret;
    char write_buf[]={0x05,reg,mask,value}; //SPI写缓冲区，用于发送修改寄存器位命令
    ret =spi_write(spi_dev,write_buf,sizeof(write_buf)); //发送SPI写命令
    if(ret<0){
        printk("mcp2515_change_regbit error\n");
    }
 }


static ssize_t spi_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{

    char r_kbuf[13]={0}; //内核缓冲区，用于存储从设备读取的数据
    int i;
    int ret;

 //等待接收缓冲区满标志位被设置
    while(!(mcp2515_read_reg(CANINTF)&(1<<0)));
 //从接收缓冲区读取数据到内核缓冲区
    for(i=0;i<sizeof(r_kbuf);i++){
        r_kbuf[i]=mcp2515_read_reg(0x61+i);
    }
 //清除接收缓冲区满标志位
    mcp2515_change_regbit(CANINTF,0x01,0x00);

 //将内核缓冲区的数据复制到用户缓冲区
    ret = copy_to_user(buf,r_kbuf,size);
    if(ret){
        printk("copy_to_userr_kbufiserror\n");
        return -1; //返回-1表示复制数据失败
    }
    return 0; //返回0表示成功读取数据

}

static ssize_t spi_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
    char w_kbuf[13]={0};
    int ret;
    int i;


    //设置TXB0CTRL寄存器的部分位
    mcp2515_change_regbit(TXB0CTRL,0x03,0x03);

    //从用户空间复制数据到内核缓冲区
    ret = copy_from_user(w_kbuf,buf,size);
    if(ret){
        printk("copy_from_user  w_kbuf is error\n");
        return -1;
    }

    //将数据写入MCP2515寄存器
    for(i=0;i<sizeof(w_kbuf);i++){
        mcp2515_write_reg(0x31+i,w_kbuf[i]);
    }

    //设置TXB0CTRL寄存器的部分位，启动发送
    mcp2515_change_regbit(TXB0CTRL,0x08,0x08);
    //等待发送完成
    while(!(mcp2515_read_reg(CANINTF)&(1<<2)));
    //清除发送完成标志
    mcp2515_change_regbit(CANINTF,0x04,0x00);

    return size;
}

static int spi_drv_open(struct inode * inod, struct file * fd)
{
    return 0;
}

static int spi_drv_release(struct inode * inod, struct file * fd)
{
    return 0;
}


static struct file_operations mcp2515_drv = {
    .owner = THIS_MODULE,
    .read    = spi_drv_read,
	.write   = spi_drv_write,
	.open    = spi_drv_open,
    .release = spi_drv_release,
};


static int	mcp2515_probe(struct spi_device *spi)
{   
    char value;

    g_spi = spi;
    major = register_chrdev(0, "mcp2515_drv", &mcp2515_drv);
    spi_class = class_create(THIS_MODULE, "mcp2515_class");
    if(IS_ERR(spi_class))
    {
        printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		unregister_chrdev(major, "mcp2515_drv");
		return PTR_ERR(spi_class);
    }

    spi_device = device_create(spi_class, NULL, MKDEV(major, 0), NULL, "mcp2515");
    if(IS_ERR(spi_device))
    {
        printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		return PTR_ERR(spi_device);
    }


    mcp2515_reset(); //复位MCP2515设备
    value = mcp2515_read_reg(0x0e); //读取寄存器值
    printk("value is %x \n",value); //打印读取的值

    /*配置CNF1、CNF2、CNF3、、RXB0CTRL、CANINTE寄存器的值*/
    mcp2515_write_reg(CNF1,0x01); //写入寄存器配置值
    mcp2515_write_reg(CNF2,0xb1);
    mcp2515_write_reg(CNF3,0x05);
    mcp2515_write_reg(RXB0CTRL,0x60);
    mcp2515_write_reg(CANINTE,0x05);

    mcp2515_change_regbit(CANCTRL,0xe0,0x40);
    value = mcp2515_read_reg(0x0e); //读取寄存器值
    printk("value is %x \n",value); //打印读取的值

    return 0;
}

static int	mcp2515_remove(struct spi_device *spi)
{
    printk("mcp2515_remove run");

    device_destroy(spi_class, MKDEV(major, 0));
	class_destroy(spi_class);
	unregister_chrdev(major, "mcp2515_drv");
    return 0;
}

static const struct of_device_id mcp2515_of_match_table[] = {
   {.compatible="hhk,mcp2515"},
   {},
};


static const struct spi_device_id mcp2515_id_table[] = {
    {"hhk,mcp2515",0},
    {}
};


struct spi_driver spi_drv = {
    .id_table = mcp2515_id_table,
    .probe = mcp2515_probe,
    .remove = mcp2515_remove,
    .driver = {
        .name = "hhk_mcp2515",       //驱动名字
        .owner = THIS_MODULE,
        .of_match_table = mcp2515_of_match_table,   //设备树匹配码
    },

};

static int __init mcp2515_drv_init(void)
{
    return spi_register_driver(&spi_drv);
}

static void __exit mcp2515_drv_exit(void)
{
    spi_unregister_driver(&spi_drv);
}


module_init(mcp2515_drv_init);
module_exit(mcp2515_drv_exit);

MODULE_LICENSE("GPL");